﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using McTools.Xrm.Connection;
using MetadataDocumentationGenerator.Controls;
using MetadataDocumentationGenerator.DelegatesHelpers;
using MetadataDocumentationGenerator.Dialog;
using MetadataDocumentationGenerator.Helpers;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;

namespace MetadataDocumentationGenerator
{
    public sealed partial class MainForm : Form
    {
        #region Variables

        /// <summary>
        /// Crm organization service
        /// </summary>
        IOrganizationService _service;

        /// <summary>
        /// Connection manager
        /// </summary>
        readonly ConnectionManager _cManager;

        /// <summary>
        /// Control that holds list of connections
        /// </summary>
        readonly CrmConnectionStatusBar _ccsb;

        private GenerationSettings _settings;
        private int _currentStep = 1;
        private int _currentEntity;
        private readonly Dictionary<int, string> _entities = new Dictionary<int, string>();
        private List<EntityMetadata> _entityList; 

        #endregion Variables

        #region Constructor

        /// <summary>
        /// Initializes a new instance of class MainForm
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            _entityList = new List<EntityMetadata>();

            // Displays application version
            Text = string.Format("{0} (v{1})", Text, Assembly.GetExecutingAssembly().GetName().Version);

            // Prepare connection statusbar control
            _cManager = new ConnectionManager(this);
            _cManager.ConnectionSucceed += CManagerConnectionSucceed;
            _cManager.ConnectionFailed += CManagerConnectionFailed;
            _cManager.StepChanged += CManagerStepChanged;

            _ccsb = new CrmConnectionStatusBar(_cManager) {BackColor = System.Drawing.Color.White};
            Controls.Add(_ccsb);

            tTip.SetToolTip(pbBug, "Submit a bug request");
            tTip.SetToolTip(pbComment, "Start a discussion");
            tTip.SetToolTip(pbDonate, "Donate using PayPal");
            tTip.SetToolTip(pbRate, "Rate this tool");
            tTip.SetToolTip(pbNetwork, "Define a custom proxy");
        }

        #endregion Constructor

        #region Connection handlers

        void CManagerStepChanged(object sender, StepChangedEventArgs e)
        {
            LabelDelegates.SetColor(lblConnectionSteps, Color.Black);
            LabelDelegates.SetText(lblConnectionSteps, e.CurrentStep);
        }

        void CManagerConnectionFailed(object sender, ConnectionFailedEventArgs e)
        {
            LabelDelegates.SetColor(lblConnectionSteps, Color.Red);
            LabelDelegates.SetText(lblConnectionSteps, e.FailureReason);

            btnConnect.Enabled = true;
            pbNetwork.Enabled = true;
        }

        void CManagerConnectionSucceed(object sender, ConnectionSucceedEventArgs e)
        {
            _service = e.OrganizationService;
            _ccsb.SetConnectionStatus(true, e.ConnectionDetail);
            _ccsb.SetMessage(string.Empty);
            _ccsb.RebuildConnectionList();

            var bwEntities = new BackgroundWorker();
            bwEntities.DoWork += BwEntitiesDoWork;
            bwEntities.RunWorkerCompleted += BwEntitiesRunWorkerCompleted;
            bwEntities.RunWorkerAsync();
        }

        void BwEntitiesRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            LabelDelegates.SetText(lblConnectionSteps, string.Empty);

            CommonDelegates.SetCursor(this, Cursor = Cursors.Default);

            pnlConnection.Visible = false;
            btnNext.Visible = true;
            btnConnect.Enabled = true;
            pbNetwork.Enabled = true;
        }

        void BwEntitiesDoWork(object sender, DoWorkEventArgs e)
        {
            CommonDelegates.SetCursor(this, Cursors.WaitCursor);
            LabelDelegates.SetText(lblConnectionSteps, "Loading entities... (This can take few minutes depending on the number of entities)");
            MetadataHelper.RetrieveEntities(_service, _entityList);
        }

        #endregion

        private void MainFormLoad(object sender, EventArgs e)
        {
            pnlSteps.Controls.Add(new Step1());
        }

        private void BtnNextClick(object sender, EventArgs e)
        {
            switch (_currentStep)
            {
                case 1:
                    {
                        if(_settings == null)
                            _settings = ((IStepControl) pnlSteps.Controls[0]).GetSettings();
                        
                        if (_settings != null)
                        {
                            var reviewSettings = ((Step1) pnlSteps.Controls[0]).ReviewSettings;

                            pnlSteps.Controls.Clear();

                            if (reviewSettings)
                            {
                                var step = new Step2(_settings, _service, _entityList);
                                pnlSteps.Controls.Add(step);

                                _currentStep = 2;

                                btnPrevious.Visible = true;
                                btnReset.Visible = true;
                            }
                            else
                            {
                                var loadingForm = new EntityLoad(_entityList, _settings.EntitiesToProceed, _service);
                                loadingForm.ShowDialog(this);

                                var step = new Step5(_settings, _service, _entityList);
                                step.GenerationFinished += StepGenerationFinished;
                                pnlSteps.Controls.Add(step);
                                _currentStep = 5;

                                btnNext.Visible = false;
                                btnPrevious.Visible = false;
                                btnReset.Visible = false;
                            }
                        }
                    }
                    break;
                case 2:
                    {
                        _settings = ((IStepControl)pnlSteps.Controls[0]).GetSettings();
                        
                        if (_settings != null)
                        {
                            pnlSteps.Controls.Clear();

                            if (_settings.AttributesSelection == AttributeSelectionOption.AttributeManualySelected)
                            {
                                _currentEntity++;

                                if(_entities.Count == 0)
                                {
                                    var index = 1;
                                    foreach(var emd in _settings.EntitiesToProceed)
                                    {
                                        _entities.Add(index++, emd.Name);
                                    }
                                }

                               
                                var step = new Step3(_settings, _service,  _entityList.Find(x => x.LogicalName == _entities[_currentEntity]));
                                pnlSteps.Controls.Add(step);
                                _currentStep = 3;
                            }
                            else
                            {
                                var step = new Step4(_settings, _service);
                                pnlSteps.Controls.Add(step);
                                _currentStep = 4;
                            }
                        }
                    }
                    break;
                case 3:
                    {
                        _settings = ((IStepControl)pnlSteps.Controls[0]).GetSettings();
                        if (_settings != null)
                        {
                            pnlSteps.Controls.Clear();
                            
                            if (_settings.AttributesSelection == AttributeSelectionOption.AttributeManualySelected)
                            {
                                _currentEntity++;

                                if (_entities.ContainsKey(_currentEntity))
                                {
                                    var step = new Step3(_settings, _service, _entityList.Find(x => x.LogicalName == _entities[_currentEntity]));
                                    pnlSteps.Controls.Add(step);
                                }
                                else
                                {
                                    _currentEntity--;
                                    var step = new Step4(_settings, _service);
                                    pnlSteps.Controls.Add(step);
                                    _currentStep = 4;
                                }
                            }
                        }
                    }
                    break;
                case 4:
                    {
                        _settings = ((IStepControl)pnlSteps.Controls[0]).GetSettings();
                        if (_settings != null)
                        {
                            pnlSteps.Controls.Clear();
                            var step = new Step5(_settings, _service, _entityList);
                            step.GenerationFinished += StepGenerationFinished;
                            pnlSteps.Controls.Add(step);
                            _currentStep = 5;

                            btnNext.Visible = false;
                            btnPrevious.Visible = false;
                            btnReset.Visible = false;
                        }
                    }
                    break;
            }
        }

        private void BtnPreviousClick(object sender, EventArgs e)
        {
            switch (_currentStep)
            {
                case 2:
                    {
                        _settings = null;
                        _currentStep = 1;
                        pnlSteps.Controls.Clear();

                        var step = new Step1();
                        pnlSteps.Controls.Add(step);
                    }
                    break;
                case 3:
                    {
                        pnlSteps.Controls.Clear();

                        if(_currentEntity == 1)
                        {
                            _currentEntity--;
                            _currentStep = 2;

                            var step = new Step2(_settings, _service, _entityList);
                            pnlSteps.Controls.Add(step);
                        }
                        else
                        {
                            _currentEntity--;

                            var step = new Step3(_settings, _service, _entityList.Find(x => x.LogicalName == _entities[_currentEntity]));
                            pnlSteps.Controls.Add(step);
                        }
                    }
                    break;
                case 4:
                    {
                        pnlSteps.Controls.Clear();

                        if(_settings.AttributesSelection == AttributeSelectionOption.AttributeManualySelected)
                        {
                            _currentStep = 3;
                            var step = new Step3(_settings, _service, _entityList.Find(x => x.LogicalName == _entities[_currentEntity]));
                            pnlSteps.Controls.Add(step);
                        }
                        else
                        {
                            _currentStep = 2;
                            var step = new Step2(_settings, _service, _entityList);
                            pnlSteps.Controls.Add(step);
                        }
                    }
                    break;
                case 6:
                    {
                        pnlSteps.Controls.Clear();
                        var step = new Step4( _settings, _service);
                        pnlSteps.Controls.Add(step);
                        _currentStep = 4;
                        btnNext.Visible = true;
                        btnNext.Enabled = true;
                    }
                    break;
            }
        }

        private void BtnResetClick(object sender, EventArgs e)
        {
            _currentStep = 1;
            _settings = null;
            pnlSteps.Controls.Clear();
            pnlSteps.Controls.Add(new Step1());
            btnNext.Visible = true;
            btnNext.Enabled = true;
        }

        void StepGenerationFinished(object sender, GenerationFinishedEventArgs e)
        {
            pnlSteps.Controls.Clear();

            if (e.FilePath != null)
            {
                var step = new Step6(_settings, e.FilePath);
                pnlSteps.Controls.Add(step);
                _currentStep = 6;
                btnNext.Visible = true;
                btnNext.Enabled = false;
            }
            else
            {
                var step = new Step4(_settings, _service);
                pnlSteps.Controls.Add(step);
                _currentStep = 4;
                btnNext.Visible = true;
                btnNext.Enabled = true;
            }

            btnPrevious.Visible = true;
            btnReset.Visible = true;
        }

        private void BtnConnectClick(object sender, EventArgs e)
        {
            btnConnect.Enabled = false;
            pbNetwork.Enabled = false;

            _cManager.AskForConnection(null);
        }

        private void PbNetworkClick(object sender, EventArgs e)
        {
            _cManager.EditProxySettings(this);
        }

        private void PbDonateClick(object sender, EventArgs e)
        {
            var url =
                string.Format(
                    "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business={0}&lc={1}&item_name={2}&currency_code={3}&bn=PP%2dDonationsBF",
                    "tanguy92@hotmail.com",
                    "FR",
                    "Donation%20for%20MSCRM%20Tools%20-%20metadatadocgenerator",
                    "EUR");

            Process.Start(url);
        }

        private void PbCommentClick(object sender, EventArgs e)
        {
            Process.Start("http://metadatadocgenerator.codeplex.com/discussions");
        }

        private void PbBugClick(object sender, EventArgs e)
        {
            Process.Start("http://metadatadocgenerator.codeplex.com/WorkItem/Create");
        }

        private void PbRateClick(object sender, EventArgs e)
        {
            Process.Start("http://metadatadocgenerator.codeplex.com/releases");
        }
    }
}
